package _3network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Pattern;

/**
 * @description:
 * @author: wang zhen
 * @create: 2021-11-30 14:16
 */
public class IPutil {

    /** IP 地址校验的正则表达式 */
    private static final Pattern IPV4_PATTERN = Pattern.compile("^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");

    /**  获取 IP 地址的服务列表 */
    private static final String[] IPV4_SERVICES = {
            "http://checkip.amazonaws.com/",
            "https://ipv4.icanhazip.com/",
            "http://bot.whatismyipaddress.com/",
            "http://ip.03k.org/"
            // and so on ...
    };

    /**
     * 获取局域网IP
     * @return
     * @throws UnknownHostException
     */
    public static String getLocalIp() throws UnknownHostException {
        return InetAddress.getLocalHost().getHostAddress();
    }

    /**
     * 获取公网IP
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static String getInterIP() throws ExecutionException, InterruptedException {
        List<Callable<String>> callables = new ArrayList<>();
        for (String ipService : IPV4_SERVICES) {
            callables.add(() -> get(ipService));
        }


        /**
         * 线程池的 ExecutorService.invokeAny(callables) 方法用于并发执行多个线程，并拿到最快的执行成功的线程的返回值，
         * 只要有一个执行成功，其他失败的任务都会忽略。但是如果全部失败，例如本机根本就没有连外网，那么就会抛出 ExecutionException 异常
         */
        ExecutorService executorService = Executors.newCachedThreadPool();
        try {
            // 返回第一个成功获取的 IP
            return executorService.invokeAny(callables);
        } finally {
            executorService.shutdown();
        }

    }


    private static String get(String url) throws IOException {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(new URL(url).openStream()))) {
            String ip = in.readLine();
            if (IPV4_PATTERN.matcher(ip).matches()) {
                return ip;
            } else {
                throw new IOException("invalid IPv4 address: " + ip);
            }
        }
    }
}
